package tw.arduino.view;

import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Properties;

import jcckit.Graphics2DPlotCanvas;
import jcckit.GraphicsPlotCanvas;
import jcckit.data.DataCurve;
import jcckit.data.DataPlot;
import jcckit.data.DataPoint;
import jcckit.util.ConfigParameters;
import jcckit.util.PropertiesBasedConfigData;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.layout.GridData;
import java.awt.Frame;
import org.eclipse.swt.awt.SWT_AWT;
import javax.swing.JRootPane;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import com.swtdesigner.SWTResourceManager;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.custom.StyledText;
import java.applet.Applet;
import java.awt.Graphics;


public class ThreeDurino extends Composite {

	private double _b = 8.0 / 3;
	private double _sigma = 10;
	private double _r = 28;
	private double _dt = 0.015;
	private double[] _x = new double[3];
	private double[] _xDot1 = new double[3];
	private double[] _xDot2 = new double[3];
	private double[][] _walk = new double[50][2];
	private int _walkIndex;
	private DataPlot _dataPlot;
	private Thread _animationThread;
	Composite composite_2;
	public static Frame frame;
	public static JRootPane rootPane;
	public static Panel panel;

	public ThreeDurino(Composite parent, int style) {
		super(parent, style);
		MainFrame.display.syncExec(new Runnable() {
			public void run() {
				ThreeDurinox();
			}
		});

	}
	public void ThreeDurinox() {
//		super(parent, style);
		setLayout(new GridLayout());

		SashForm sashForm = new SashForm(this, SWT.NONE);
		sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));

		Composite composite = new Composite(sashForm, SWT.NONE);
		composite.setLayout(new GridLayout(1, false));

		ToolBar toolBar = new ToolBar(composite, SWT.FLAT | SWT.RIGHT);
		toolBar.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));

		ToolItem tltmStart = new ToolItem(toolBar, SWT.NONE);
		tltmStart.setImage(SWTResourceManager.getImage(ThreeDurino.class, "/images/gif/methpub_obj.gif"));
		tltmStart.setText("OpenPort");

		ToolItem tltmRefresh = new ToolItem(toolBar, SWT.CHECK);
		tltmRefresh.setSelection(true);
		tltmRefresh.setImage(SWTResourceManager.getImage(ThreeDurino.class, "/images/gif/refresh.gif"));
		tltmRefresh.setText("Refresh");

		Group grpXAxis = new Group(composite, SWT.NONE);
		grpXAxis.setText("X Axis");
		grpXAxis.setLayout(new GridLayout(1, false));
		grpXAxis.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));

		Scale scale = new Scale(grpXAxis, SWT.NONE);
		scale.setMaximum(1023);
		scale.setSelection(512);
		scale.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));

		Group grpYAxis = new Group(composite, SWT.NONE);
		grpYAxis.setText("Y Axis");
		grpYAxis.setLayout(new GridLayout(1, false));
		grpYAxis.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));

		Scale scale_1 = new Scale(grpYAxis, SWT.NONE);
		scale_1.setMaximum(1023);
		scale_1.setSelection(512);
		scale_1.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));

		Group grpZAxis = new Group(composite, SWT.NONE);
		grpZAxis.setText("Z Axis");
		grpZAxis.setLayout(new GridLayout(1, false));
		grpZAxis.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));

		Scale scale_2 = new Scale(grpZAxis, SWT.NONE);
		scale_2.setMaximum(1023);
		scale_2.setSelection(512);
		scale_2.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));

		Group grpDefaultArduinoCode = new Group(composite, SWT.NONE);
		grpDefaultArduinoCode.setText("Default Arduino Code");
		grpDefaultArduinoCode.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		grpDefaultArduinoCode.setLayout(new GridLayout(1, false));

		StyledText styledText = new StyledText(grpDefaultArduinoCode, SWT.BORDER | SWT.WRAP);
		styledText.setText("http://arduino.tw/allarticlesindex/bt-rfid-xbee-ir/228-xbee-xbee-arduino.html");
		styledText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));

		Composite composite_1 = new Composite(sashForm, SWT.NONE);
		composite_1.setLayout(new GridLayout(1, false));

		composite_2 = new Composite(composite_1, SWT.EMBEDDED);
		composite_2.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));

//		MainFrame.display.syncExec(new Runnable() {
//			public void run() {
				init();
//			}
//		});
		sashForm.setWeights(new int[] { 1, 1 });

	}
	public void init() {
		frame = SWT_AWT.new_Frame(composite_2);
		
		panel = new Panel();
		frame.add(panel);
		panel.setLayout(new BorderLayout(0, 0));
		
		rootPane = new JRootPane();
		panel.add(rootPane);
//		 GraphicsPlotCanvas plotCanvas = createPlotCanvas("true".equals(getParameter("graphics2D")));

		GraphicsPlotCanvas plotCanvas = createPlotCanvas(false);
		
		_dataPlot = new DataPlot();
		_dataPlot.addElement(new DataCurve("")); // dummy
		reset();
		plotCanvas.connect(_dataPlot);
		
		panel.setLayout(new BorderLayout());
		panel.add(plotCanvas.getGraphicsCanvas(), BorderLayout.CENTER);
		panel.add(createControlPanel(), BorderLayout.SOUTH);
	}

	@Override
	protected void checkSubclass() {
		// Disable the check that prevents subclassing of SWT components
	}


	private GraphicsPlotCanvas createPlotCanvas(boolean graphics2D) {
		Properties props = new Properties();
		ConfigParameters config = new ConfigParameters(new PropertiesBasedConfigData(props));
		props.put("foreground", "0xffffff");
		props.put("background", "0");
		props.put("plot/legendVisible", "false");
		props.put("plot/coordinateSystem/xAxis/minimum", "-20");
		props.put("plot/coordinateSystem/xAxis/maximum", "20");
		props.put("plot/coordinateSystem/xAxis/ticLabelFormat", "%d");
		props.put("plot/coordinateSystem/yAxis/axisLabel", "z");
		props.put("plot/coordinateSystem/yAxis/minimum", "0");
		props.put("plot/coordinateSystem/yAxis/maximum", "50");
		props.put("plot/coordinateSystem/yAxis/ticLabelFormat", "%d");
		props.put("plot/curveFactory/definitions", "curve");
		props.put("plot/curveFactory/curve/initialHintForNextPoint/className", "jcckit.plot.ShapeAttributesHint");
		props.put("plot/curveFactory/curve/initialHintForNextPoint/" + "initialAttributes/fillColor", "0x50a");
		props.put("plot/curveFactory/curve/initialHintForNextPoint/" + "fillColorHSBIncrement", "0.0 0.0 0.018");
		props.put("plot/curveFactory/curve/withLine", "false");
		props.put("plot/curveFactory/curve/symbolFactory/className", "jcckit.plot.CircleSymbolFactory");
		props.put("plot/curveFactory/curve/symbolFactory/size", "0.015");

		return graphics2D ? new Graphics2DPlotCanvas(config) : new GraphicsPlotCanvas(config);
	}

	private Panel createControlPanel() {
		Panel controlPanel = new Panel();
		Button startButton = new Button("start");
		startButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				_animationThread = new Thread() {
					public void run() {
						while (_animationThread != null) {
							try {
								Thread.sleep(50);
							} catch (InterruptedException e) {
							}
							next();
						}
					}
				};
				_animationThread.start();
			}
		});
		controlPanel.add(startButton);
		Button stopButton = new Button("stop");
		stopButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				_animationThread = null;
			}
		});
		controlPanel.add(stopButton);
		Button resetButton = new Button("reset");
		resetButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				reset();
			}
		});
		controlPanel.add(resetButton);

		return controlPanel;
	}

	private void reset() {
		_x[0] = 10 * (Math.random() - 0.5);
		_x[1] = 10 * (Math.random() - 0.5);
		_x[2] = 10;
		for (int i = 0; i < _walk.length; i++) {
			_walk[i][0] = _x[0];
			_walk[i][1] = _x[2];
		}
		updateCurve();
	}

	private void next() {
		integrate();
		_walk[_walkIndex][0] = _x[0];
		_walk[_walkIndex][1] = _x[2];
		_walkIndex = (_walkIndex + 1) % _walk.length;
		updateCurve();
	}

	/**
	 * Integrates differential equations by using a second-order Runge-Kutta
	 * method.
	 */
	private void integrate() {
		calculateDerivatives(_x, _xDot1);
		for (int i = 0; i < _x.length; i++) {
			_x[i] += _dt * _xDot1[i];
		}
		calculateDerivatives(_x, _xDot2);
		for (int i = 0; i < _x.length; i++) {
			_x[i] += 0.5 * _dt * (_xDot2[i] - _xDot1[i]);
		}
	}

	private void calculateDerivatives(double[] x, double[] xDot) {
		xDot[0] = _sigma * (x[1] - x[0]);
		xDot[1] = _r * x[0] - x[1] - x[0] * x[2];
		xDot[2] = x[0] * x[1] - _b * x[2];
	}

	private void updateCurve() {
		DataCurve curve = new DataCurve("trajectory");
		for (int i = 0; i < _walk.length; i++) {
			int index = (_walkIndex + i) % _walk.length;
			curve.addElement(new DataPoint(_walk[index][0], _walk[index][1]));
		}
		_dataPlot.replaceElementAt(0, curve);
	}

}
